home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / CUGUK / COMMS / C035.ZIP / JMODEM_A.C < prev    next >
Text File  |  1990-02-17  |  27KB  |  461 lines

  1. /****************************************************************************/
  2. /*    FILE JMODEM_A.C                                                       */
  3. /*                                                                          */
  4. /*    The JMODEM protocol            MicroSoft (r)  'C' V5.1                */
  5. /*    Created 03-FEB-1990            Richard B. Johnson                     */
  6. /*                                   405 Broughton Drive                    */
  7. /*                                   Beverly, Massachusetts 01915           */
  8. /*                                   BBS (508) 922-3166                     */
  9. /*                                                                          */
  10. /*    An external protocol for high-speed data transmission.                */
  11. /*                                                                          */
  12. /*    This is the MAIN module                                               */
  13. /*    The required modules are:                                             */
  14. /*    JMODEM.H    (function prototypes and structures)                      */
  15. /*    UART.H      (8250 UART parameters)                                    */
  16. /*    SCREEN.H    (function protypes and structures for the screen)         */
  17. /*    JMODEM_A.C  (this module)                                             */
  18. /*    JMODEM_B.C  (memory allocation and input parsing)                     */
  19. /*    JMODEM_C.C  (all file I/O)                                            */
  20. /*    JMODEM_D.C  (encode/decode and CRC routines)                          */
  21. /*    JMODEM_E.C  (communications I/O routines)                             */
  22. /*    JMODEM_F.C  (the screen I/O routines)                                 */
  23. /*    JMODEM.     (The MAKE file )                                          */
  24. /*                                                                          */
  25. /*    This program requires about 67k of free RAM to execute properly.      */
  26. /*    If you have 66k or less, it will execute, but the screens will        */
  27. /*    not be written or replaced properly. If you have only 64k, the        */
  28. /*    program will exit with an error message.                              */
  29. /*                                                                          */
  30. /****************************************************************************/
  31. #include <stdlib.h>                     /* Used for _free()                */
  32. #include <stdio.h>                      /* Used for NULL value             */
  33. #include <string.h>                     /* Used for _memcpy()              */
  34. #include <time.h>                       /* Used for absolute time          */
  35. #include "jmodem.h"                     /* JMODEM primatives               */
  36. #pragma intrinsic (memcpy)              /* In-line code                    */
  37. /****************************************************************************/
  38. /*                   Global pointers and allocation                         */
  39. /****************************************************************************/
  40. short  handle;                          /* For file I/O                     */
  41. SYS syst;                               /* Structure for JMODEM status      */
  42. unsigned short user_abort = 0;          /* User abort flag                  */
  43. unsigned char *in_buffer;               /* Pointer to input buffer          */
  44. unsigned char *out_buffer;              /* Pointer to output buffer         */
  45. unsigned char *comp_buffer;             /* Pointer to compression buffer    */
  46. unsigned char *file_buffer;             /* Pointer to file buffer           */
  47. unsigned char *int_buffer;              /* Pointer to interrupt buffer      */
  48. unsigned long start;                    /* Start time                       */
  49. unsigned long finish;                   /* End time                         */
  50. unsigned short *buf_len;                /* Used to get/set block length     */
  51. JBUF *buff;                             /* A pointer for the JMODEM block   */
  52. char abrt[]  = "Aborted!";              /* Four messages                    */
  53. char okay[]  = "Okay    ";
  54. char retry[] = "Retry   ";
  55. char done[]  = "Done!   ";
  56. /****************************************************************************/
  57. /*                               C O D E                                    */
  58. /****************************************************************************/
  59. short main (short argc, char *argv[])
  60. {
  61.     unsigned short status=0;            /* TX and RX status                 */
  62.     unsigned short tries;               /* Attempts to send a file          */
  63.     unsigned short cmp_size;            /* Size after compression           */
  64.     unsigned short data_written;        /* Data written to the file         */
  65.     unsigned short data_read;           /* Data read from the file          */
  66.     char *file_name;                    /* filename                         */
  67.     char *function;                     /* Receive, Transmit                */
  68.     char *com_port;                     /* Communications adapter port      */
  69.  
  70.     file_name = get_inp (argc, argv);   /* Get file name                    */
  71.     if (file_name == NULL )
  72.     {
  73.         disp();                         /* Display usage message            */
  74.         return JM_FNF;
  75.     }
  76.     function  = get_fun (argc, argv);   /* Get function 'R' or 'S'          */
  77.     if (function == NULL)
  78.     {
  79.         disp();                         /* Display usage message            */
  80.         return JM_CMD;
  81.     }
  82.     com_port  = get_prt (argc, argv);   /* Get port '1 to 4 '               */
  83.     if (com_port == NULL)
  84.     {
  85.         disp();                         /* Display usage message            */
  86.         return JM_CMD;
  87.     }
  88.     port = get_port(*com_port);         /* Convert port to an offset        */
  89. /****************************************************************************/
  90. /*                          Allocate buffers                                */
  91. /****************************************************************************/
  92.     in_buffer = allocate_memory(DAT_LEN);  /* Get some memory for input     */
  93.     if (in_buffer == NULL)
  94.         return JM_MEM;                     /* No memory available           */
  95.     out_buffer = allocate_memory(DAT_LEN); /* Get some memory for output    */
  96.     if (out_buffer == NULL)
  97.         return JM_MEM;                     /* No memory available           */
  98.     comp_buffer=allocate_memory(DAT_LEN);  /* Get memory for compression    */
  99.     if (comp_buffer == NULL)
  100.         return JM_MEM;                     /* No memory available           */
  101.     file_buffer=allocate_memory(DAT_LEN);  /* Get memory for file buffer    */
  102.     if (file_buffer == NULL)
  103.         return JM_MEM;                     /* No memory available           */
  104.     int_buffer =allocate_memory(DAT_LEN);  /* Memory for interrupt buffer   */
  105.     if (int_buffer == NULL)
  106.         return JM_MEM;                     /* No memory available           */
  107. /****************************************************************************/
  108.  
  109.     screen (SCR_SGN,NULL,NULL);            /* Write signon screen           */
  110.     syst.s_len = BLK_SIZ;
  111.     syst.s_byt = 0;
  112.     syst.s_blk = 0;
  113.     syst.s_sta = okay;
  114.     switch(*function)                     /* Functions are TX and RX       */
  115.     {
  116. /****************************************************************************/
  117. /*                          Receive JMODEM file                             */
  118. /****************************************************************************/
  119.     case 'R':
  120.         {
  121.             if (!file_io(CREATE, &handle, &file_name, NULL) )
  122.             {
  123.                 buff = (JBUF *) in_buffer;            /* Assign type JBUF   */
  124.                 open_chan(port);                      /* Open com channel   */
  125.                 screen (SCR_STA,NULL,NULL);           /* Write status block */
  126.                 status = rx_sync();                   /* Synchronize        */
  127.                 if (!status)
  128.                     screen (SCR_SYR,NULL,NULL);
  129.                 data_written = 0xFFFF;
  130.                 tries = 10;                /* Attempts to receive */
  131.                 while (    (data_written)             /* Write file okay   */
  132.                         && (!user_abort )             /* No break key      */
  133.                         && (!status     )             /* Recev block okay  */
  134.                         && (tries--)    )             /* 10 retries        */
  135.                 {
  136.                     time(&start);                     /* Get starting time */
  137.             screen (SCR_SYS,&syst,NULL);      /* Show status block */
  138.                     status = recv_blk (               /* Receive data-block*/
  139.                              &syst.s_len,             /* Block length      */
  140.                              in_buffer);              /* Input buffer      */
  141.                     if (status)                       /* If bad            */
  142.                         break;                        /* Abort the WHILE   */
  143.                     if( (!(calc_crc(GET_CRC,          /* Calculate CRC     */
  144.                           syst.s_len,                 /* Amount to check   */
  145.                           in_buffer) ))               /* Receiver buffer   */
  146.               && ( buff->blk_num ==           /* Check             */
  147.                          (unsigned char)
  148.                          (syst.s_blk +1)))            /* Block number      */
  149.                     {
  150.                         syst.s_sta = okay;            /* Text pointer      */
  151.                         tries=10;                     /* Reset count       */
  152.                         syst.s_len -= OVRHD;          /* Subtract overhead */
  153.                         *out_buffer = ACK;            /* Good              */
  154.                         write_chan(1,out_buffer);     /* Send the ACK      */
  155.  
  156.                         /* If data was compressed                          */
  157.             if ( (buff->blk_typ & COMP) == COMP)
  158.                         {
  159.                              syst.s_len = decode (    /* Decode the data   */
  160.                                       syst.s_len,     /* Data-block length */
  161.                      &buff->blk_dat,  /* Where to start    */
  162.                                      file_buffer);    /* Where to put data */
  163.                         }
  164.                         else
  165.                         /* Data was normal (not compressed, just copy )    */
  166.                         {
  167.                             memcpy (file_buffer,&buff->blk_dat,syst.s_len);
  168.                         }
  169.                         /* Write to the file                                */
  170.                         data_written = file_io( WRITE ,  /* Function        */
  171.                                          &handle,        /* File handle     */
  172.                                          &file_buffer ,  /* Where data is   */
  173.                                          syst.s_len   ); /* Amount to write */
  174.                         syst.s_byt += data_written;      /* Total bytes     */
  175.                         syst.s_blk++;                    /* Block number    */
  176.                         time(&finish);                   /* Get end time    */
  177.                         if (finish - start)              /* Check div/0     */
  178.                             syst.s_cps = (short)         /* Calc Block CPS  */
  179.                             (data_written / (finish - start) );
  180.  
  181.                             /* Check for end-of-file                        */
  182.                         if ( (buff->blk_typ & EOF_) == EOF_)
  183.                         {                       /* This was the end of file */
  184.                             file_io(CLOSE,               /* Function        */
  185.                                    &handle,              /* Open handle     */
  186.                                    &file_name,           /* Name not used   */
  187.                                    NULL);                /* Buffer not used */
  188.                             write_chan(1,out_buffer);    /* Send the ACK    */
  189.                             close_chan(port);            /* Close the port  */
  190.                             status = JM_NRM;             /* Set status      */
  191.                             goto cleanup;                /* exit routine    */
  192.                         }
  193.                     }
  194.                     else
  195.                     {
  196.                         *out_buffer = NAK;              /* Bad block        */
  197.                         syst.s_sta = retry;             /* Char pointer     */
  198.                         write_chan(1,out_buffer);       /* Send the NAK     */
  199.                      }
  200.                 }
  201.                 close_chan(port);                        /* Aborted         */
  202.                 file_io(DELETE,                          /* Function        */
  203.                         &handle,                         /* File handle     */
  204.                         &file_name,                      /* Name            */
  205.                         NULL);                           /* Buffer not used */
  206.                 status = JM_ABT;
  207.         break;                                   /* Exit if() {}    */
  208.             }
  209.             else                                       /* Can't create file */
  210.             {
  211.                 status = JM_CRE;
  212.                 break;                                   /* Exit while() {} */
  213.             }
  214.         break;                                           /* Exit case 'R'   */
  215.         }
  216. /****************************************************************************/
  217. /*                          Send JMODEM file                                */
  218. /****************************************************************************/
  219.     case 'S':   /* Send JMODEM file */
  220.         {
  221.             if (!file_io(OPEN_READ, &handle, &file_name, NULL) )
  222.             {
  223.                 buff = (JBUF *)out_buffer;            /* Assign type JBUF   */
  224.         buf_len=(unsigned short *)out_buffer; /* A WORD pointer     */
  225.                 open_chan(port);                      /* Open COM port      */
  226.                 data_read = 0xFFFF;                   /* Initialize         */
  227.                 screen (SCR_STA,NULL,NULL);           /* Write status block */
  228.                 status = tx_sync();                   /* Synchronize        */
  229.                 if (!status)
  230.                     screen (SCR_SYT,NULL,NULL);
  231.                 while  (  (!user_abort)               /* Ctrl - break       */
  232.                        && (!status) )                 /* sent okay          */
  233.                 {
  234.                     time(&start);                     /* Get starting time  */
  235.                     data_read = file_io( READ       , /* Read a record      */
  236.                                        &handle      , /* File pointer       */
  237.                                        &file_buffer , /* Where to put       */
  238.                                       syst.s_len  );  /* Amount to read     */
  239.                     if (!data_read)                   /* Past end of file   */
  240.                         break;
  241.                     syst.s_byt += (long) data_read;   /* Running count      */
  242.             screen (SCR_SYS,&syst,NULL);      /* Show status block  */
  243.                     buff->blk_num = (unsigned char)
  244.                                      ++syst.s_blk;    /* Block number       */
  245.                      
  246.                     if (data_read != syst.s_len)      /* Byte request       */
  247.                         buff->blk_typ = EOF_;         /* Into control-byte  */
  248.                     else
  249.                         buff->blk_typ = NULL;         /* Normal block       */
  250.                     
  251.                     cmp_size = encode (data_read,     /* Encode size        */
  252.                                       file_buffer,    /* Source             */
  253.                                       comp_buffer);   /* Destination        */
  254.                     if ( cmp_size  < data_read  )     /* If compressed      */
  255.                     {
  256.             *buf_len = (cmp_size+OVRHD);  /* Length of block    */
  257.                         buff->blk_typ |= COMP;        /* Show compressed    */
  258.                         memcpy (&buff->blk_dat,       /* Start of data      */
  259.                                    comp_buffer,       /* From here          */
  260.                                    cmp_size);         /* This much          */
  261.                         
  262.                         calc_crc(SET_CRC,             /* Calculate CRC      */
  263.                                 cmp_size + OVRHD,     /* Length of block    */
  264.                                 out_buffer);          /* Where data is      */
  265.                         status = send_blk(            /* Send block         */
  266.                                 (cmp_size + OVRHD),   /* Block length       */
  267.                  &syst,               /* Read block ptr.    */
  268.                                  out_buffer);         /* Buffer pointer     */
  269.                     }
  270.                     else                              /* Not compressed     */
  271.                     {
  272.             *buf_len = (data_read+OVRHD); /* Length of block    */
  273.                         buff->blk_typ |= NORM;        /* Show normal data   */
  274.                         memcpy (&buff->blk_dat,       /* Copy to            */
  275.                                    file_buffer,       /* Copy from          */
  276.                                    data_read);        /* This amount        */
  277.                         calc_crc(SET_CRC,             /* Calculate CRC      */
  278.                                 (data_read + OVRHD),  /* Block length       */
  279.                                  out_buffer);         /* Buffer pointer     */
  280.                         status = send_blk(            /* Send the block     */
  281.                                  (data_read + OVRHD), /* Size of block      */
  282.                                  &syst,               /* Read size ptr      */
  283.                                  out_buffer);         /* Ptr to buffer      */
  284.                     }
  285.                     time(&finish);                    /* Get end time       */
  286.                     if (finish - start)               /* Guard div/zero     */
  287.                         syst.s_cps = (short)          /* Calc Block CPS     */
  288.                         (data_read / (finish - start) );
  289.                     if ( buff->blk_typ == EOF_)       /* Last record        */
  290.                         break;
  291.                 }
  292.                 close_chan(port);                     /* Close the port     */
  293.                 if (status)
  294.                     syst.s_sta = abrt;                /* A text pointer     */
  295.                 else
  296.                     syst.s_sta = done;                /* A text pointer     */
  297.  
  298.                 file_io(CLOSE, &handle,
  299.                         &file_name, NULL);            /* Close the file     */
  300.                 screen (SCR_SYS,&syst,NULL);          /* Show status block  */
  301.             }
  302.             else                                      /* File not found     */
  303.             {
  304.                 status = JM_FNF;
  305.             }
  306.         break;  /* End of CASE 'S' */
  307.         }
  308.     }
  309.     cleanup:
  310.     free (in_buffer);                                  /* Free  buffers     */
  311.     free (out_buffer);
  312.     free (comp_buffer);
  313.     free (file_buffer);
  314.     /* Five-second timer to display error messages */
  315.     if (status != JM_NRM)
  316.     {
  317.         time(&finish);
  318.         start = 0;
  319.         finish += 5;
  320.         while ( finish > start )
  321.             time(&start);
  322.     }
  323.     screen (SCR_END,NULL,NULL);                         /* Clear the screen */
  324.     return status;                                      /* Normal exit      */
  325. }
  326. /****************************************************************************/
  327. /*                          Send the JMODEM block                           */
  328. /****************************************************************************/
  329. unsigned short send_blk (blk_len, sys_ptr, buffer)
  330. unsigned short blk_len;
  331. SYS *sys_ptr;
  332. unsigned char *buffer;
  333. {
  334.     unsigned char ack_buf;                  /* Buffer for ACK/NAK         */
  335.     unsigned short tries = 10;              /* Attempts to send the block */
  336.     while ((tries--) && (!user_abort))
  337.     {
  338.         write_chan(blk_len,buffer);          /* Send the JMODEM block      */
  339.         flush();                             /* Clear back channel noise   */
  340.         do
  341.         {
  342.             ack_buf = NULL;                  /* Clear the return buffer    */
  343.             read_chan(1,&ack_buf);           /* Receive a response         */
  344.         } while ( (ack_buf != ACK)           /* Stay in loop until we      */
  345.                && (ack_buf != CAN)           /*  ... get something useful  */
  346.                && (ack_buf != NAK)           /* This helps re-sync in noise*/
  347.                && (ack_buf !=NULL)
  348.                && (!user_abort) );
  349.  
  350.         if (ack_buf == CAN)                  /* Check for an abort         */
  351.             break;                           /* User aborted               */
  352.         if (ack_buf == ACK)                  /* If good block              */
  353.         {
  354.             if (tries == 9)                  /* If no retries              */
  355.             {
  356.         sys_ptr->s_len += 512;        /* Increase block-size       */
  357.         if (sys_ptr->s_len > DAT_MAX) /* If too large              */
  358.             sys_ptr->s_len = DAT_MAX;
  359.             }
  360.             else
  361.             {
  362.         sys_ptr->s_len = sys_ptr->s_len >> 1; /* Div by two             */
  363.         if (sys_ptr->s_len  < 0x40)       /* If less than minimum       */
  364.         sys_ptr->s_len = 0x40;        /* Set to minimum             */
  365.             }
  366.         sys_ptr->s_sta = okay;                /* Show status is okay        */
  367.         return JM_NRM;                        /* Show good                  */
  368.         }
  369.     sys_ptr->s_sta = retry;                   /* Show a retry               */
  370.     screen (SCR_SYS, sys_ptr,NULL);           /* Write to screen            */
  371.     }
  372.     ack_buf = CAN;                        /* Send ^Xes                  */
  373.         for (tries = 0; tries <6; tries++)    /* Six times                  */
  374.             write_chan(1,&ack_buf);
  375.         return JM_ABT;                        /* Abort local program        */
  376.  
  377. }
  378. /****************************************************************************/
  379. /*                        Receive the JMODEM block                          */
  380. /****************************************************************************/
  381. unsigned short recv_blk (blk_len, buffer)
  382. unsigned short *blk_len;                  /* Pointer to the block-length   */
  383. unsigned char *buffer;                    /* Pointer to the buffer         */
  384. {
  385.     BLK *buff;                            /* Pointer type BLK              */
  386.     unsigned char nak_buf;                /* Buffer for ACK/NAK            */
  387.     unsigned short tries = 10;            /* Attempts to receive the block */
  388.     unsigned short ret_val;               /* Block length returned         */
  389.     buff = (BLK * )buffer;                /* Need pointer to 3rd BYTE      */
  390.     buf_len = (unsigned short * )buffer;  /* Need pointer to first WORD    */
  391.  
  392.     while ((tries--) && (!user_abort))
  393.     {
  394.         ret_val = read_chan(2,buffer);    /* Receive the block size        */
  395.         if (ret_val == 2)                 /* If we received the length     */
  396.         {
  397.             *blk_len = *buf_len;          /* So caller knows size          */
  398.             ret_val = read_chan(          /* Get more data                 */
  399.                       (*blk_len)-2,       /* Size to read                  */
  400.                       &buff->blok_dat);   /* Where to put it               */
  401.         if (ret_val == (*blk_len)-2)  /* If we got what we requested */
  402.         return JM_NRM;
  403.         }
  404.     nak_buf = NAK;                          /* Get a NAK                   */
  405.     write_chan(1,&nak_buf);                 /* Send to remote              */
  406.     flush();                                /* Flush the buffer            */
  407.     }
  408.     nak_buf = CAN;                          /* Send ^Xes                   */
  409.     for (tries = 0; tries <6; tries++)
  410.     write_chan(1,&nak_buf);
  411.     return JM_ABT;                          /* Abort local program        */
  412. }
  413. /****************************************************************************/
  414. /*                         Synchronize during receive                       */
  415. /****************************************************************************/
  416. unsigned short rx_sync()
  417. {
  418.     short i;
  419.     unsigned char ack_nak;              /* Single byte buffer for ACK/NAK  */
  420.     flush();                            /* Clear the interrupt buffer      */
  421.     while (!user_abort)
  422.     {
  423.         ack_nak = NULL;                 /* Clear the buffer                */
  424.         read_chan(1,&ack_nak);          /* Receive ACK, NAK, or SYN        */
  425.         if (ack_nak == CAN)             /* If a ^X                         */
  426.             break;
  427.         if ( ack_nak == ACK )           /* If a good response              */
  428.             return JM_NRM;              /* Show handshake                  */
  429.         if ( ack_nak == NAK )           /* If a good response              */
  430.         {
  431.             ack_nak = ACK;
  432.             write_chan(1,&ack_nak);     /* Send a ACK response             */
  433.         return JM_NRM;
  434.          }
  435.          ack_nak = NAK;
  436.          write_chan(1,&ack_nak);        /* Keep sending MAKs               */
  437.     }
  438.     ack_nak = CAN;
  439.     for (i=0; i<8; i++)                 /* Send 8 ^Xes                     */
  440.         write_chan(1,&ack_nak);         /* Send a response                 */
  441.     return JM_ABT;
  442. }
  443. /****************************************************************************/
  444. /*                         Synchronize during transmit                      */
  445. /****************************************************************************/
  446. unsigned short tx_sync()
  447. {
  448.     unsigned short ret_val;
  449.     ret_val = rx_sync();                /* Call same routine for receive    */
  450.     if (ret_val)                        /* If no success                    */
  451.         return ret_val;                 /* Abort routines                   */
  452.     flush();                            /* Else flush the input buffer      */
  453.     timer = 5;                          /* 5 timer-ticks to wait            */
  454.     while (timer)                       /* Wait for timer                   */
  455.         ;
  456.     return JM_NRM;                      /* Normal return                    */
  457. }
  458. /****************************************************************************/
  459. /************************ E N D  O F   M O D U L E **************************/
  460.  
  461.